%{
/*********************************************
将所有的词法分析功能均放在 yylex 函数内实现，为 +、-、*、\、(、 ) 每个运算符及整数分别定义一个单词类别，在 yylex 内实现代码，能
识别这些单词，并将单词类别返回给词法分析程序。
实现功能更强的词法分析程序，可识别并忽略空格、制表符、回车等
空白符，能识别多位十进制整数。
YACC file
**********************************************/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#ifndef YYSTYPE
#define YYSTYPE char*
#endif  // 表示yacc产生的值是字符串
int yylex();
extern int yyparse();
FILE* yyin;
void yyerror(const char* s);
%} // 定义了预处理部分

//TODO:给每个符号定义一个单词类别
%token '+' '-'
%token NUMBER
%token '*' '/'
%token '(' ')' 
%token IDENT
// 运算符优先级，前——>后，低——>高
%left '+' '-'
%left '*' '/'
%left '(' ')' 
%right UMINUS //识别负数         



%%


lines   :       lines expr ';' { printf("%s \n", $2); }
        |       lines ';'
        |
        ;
//TODO:完善表达式的规则
/*%prec UMINUS：这部分是一个语法分析器中的优先级规定。它告诉解析器，在处理一元减号时，应该将其与UMINUS优先级关联起来，以确保正确的运算顺序。*/
expr    :       expr '+' expr   {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s %s + ", $1, $3); }
        |       expr '-' expr   {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s %s - ", $1, $3); }
        |       expr '*' expr   {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s %s * ", $1, $3); }
        |       expr '/' expr   {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s %s / ", $1, $3); }
        |       '(' expr ')'    {$$ = $2; }
        |       '-' expr %prec UMINUS   {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "-%s ", $2);}
        |       NUMBER          {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s", $1); }
        |       IDENT           {$$ = (char *)malloc(50*sizeof (char));sprintf($$, "%s", $1); }
        ;
%%

// programs section

int yylex()
{
    int t;
    while(1){
        t=getchar();
        if(t==' '||t=='\t'||t=='\n'||t=='\r'){
         ;//do noting
        }else if(t>='0'&&t<='9'){
            //TODO:解析多位数字返回数字类型 
            /*yacc内部定义的变量yylval用于传递属性值*/
            int i=0;
            char tmp[50];
            while(t>='0'&&t<='9'){
            	tmp[i]=t;
            	t=getchar();
            	i++;
            }
            tmp[i]='\0';
            yylval=strdup(tmp);
            ungetc(t , stdin);
            return NUMBER;
        }else if(t=='+'){
            return '+';
        }else if(t=='-'){
            return '-';
        }//TODO:识别其他符号
        else if(t=='*'){
            return '*';
        }else if(t=='/'){
            return '/';
        }else if(t=='('){
            return '(';
        }else if(t==')'){
            return ')';
        }
        else if((t >= 'a' && t <= 'z' ) || ( t >= 'A' && t<= 'Z' ) || ( t == '_' ))
        {
            int i=0;
            char tmp[50];
            while((t >= 'a' && t <= 'z' ) || ( t >= 'A' && t<= 'Z' ) || ( t == '_' )||(t>='0'&&t<='9'))
            {
            	tmp[i]=t;
            	t=getchar();
            	i++;
            }
            tmp[i]='\0';
            yylval=strdup(tmp);
            ungetc(t , stdin);
            return IDENT;
        }
        else{
            return t;
        }
    }
}

int main(void)
{
    yyin=stdin;
    do{
        yyparse();
    }while(!feof(yyin));
    return 0;
}
void yyerror(const char* s){
    fprintf(stderr,"Parse error: %s\n",s);
    exit(1);
}
